#include "ddr_retention.h"

// Address of ddr phy register to be save and restore
const uint32_t ret_ddrphy_addr[RET_CSRS_CNT] = {
	0x1005f,	0x1015f,	0x1105f,	0x1115f,	0x1205f,	0x1215f,	0x1305f,	0x1315f,
	0x55   ,	0x1055 ,	0x2055 ,	0x3055 ,	0x4055 ,	0x5055 ,	0x6055 ,	0x7055 ,
	0x8055 ,	0x9055 ,	0x200c5,	0x2002e,	0x90204,	0x20024,	0x2003a,	0x2007d,
	0x2007c,	0x20056,	0x1004d,	0x1014d,	0x1104d,	0x1114d,	0x1204d,	0x1214d,
	0x1304d,	0x1314d,	0x10049,	0x10149,	0x11049,	0x11149,	0x12049,	0x12149,
	0x13049,	0x13149,	0x43   ,	0x1043 ,	0x2043 ,	0x3043 ,	0x4043 ,	0x5043 ,
	0x6043 ,	0x7043 ,	0x8043 ,	0x9043 ,	0x20018,	0x20075,	0x20050,	0x20008,
	0x20088,	0x200b2,	0x10043,	0x10143,	0x11043,	0x11143,	0x12043,	0x12143,
	0x13043,	0x13143,	0x200fa,	0x20019,	0x200f0,	0x200f1,	0x200f2,	0x200f3,
	0x200f4,	0x200f5,	0x200f6,	0x200f7,	0x1004a,	0x1104a,	0x1204a,	0x1304a,
	0x20025,	0x2002d,	0x2002c,	0xd0000,	0x90000,	0x90001,	0x90002,	0x90003,
	0x90004,	0x90005,	0x90029,	0x9002a,	0x9002b,	0x9002c,	0x9002d,	0x9002e,
	0x9002f,	0x90030,	0x90031,	0x90032,	0x90033,	0x90034,	0x90035,	0x90036,
	0x90037,	0x90038,	0x90039,	0x9003a,	0x9003b,	0x9003c,	0x9003d,	0x9003e,
	0x9003f,	0x90040,	0x90041,	0x90042,	0x90043,	0x90044,	0x90045,	0x90046,
	0x90047,	0x90048,	0x90049,	0x9004a,	0x9004b,	0x9004c,	0x9004d,	0x9004e,
	0x9004f,	0x90050,	0x90051,	0x90052,	0x90053,	0x90054,	0x90055,	0x90056,
	0x90057,	0x90058,	0x90059,	0x9005a,	0x9005b,	0x9005c,	0x9005d,	0x9005e,
	0x9005f,	0x90060,	0x90061,	0x90062,	0x90063,	0x90064,	0x90065,	0x90066,
	0x90067,	0x90068,	0x90069,	0x9006a,	0x9006b,	0x9006c,	0x9006d,	0x9006e,
	0x9006f,	0x90070,	0x90071,	0x90072,	0x90073,	0x90074,	0x90075,	0x90076,
	0x90077,	0x90078,	0x90079,	0x9007a,	0x9007b,	0x9007c,	0x9007d,	0x9007e,
	0x9007f,	0x90080,	0x90081,	0x90082,	0x90083,	0x90084,	0x90085,	0x90086,
	0x90087,	0x90088,	0x90089,	0x9008a,	0x9008b,	0x9008c,	0x9008d,	0x9008e,
	0x9008f,	0x90090,	0x90091,	0x90092,	0x90093,	0x90094,	0x90095,	0x90096,
	0x90097,	0x90098,	0x90099,	0x9009a,	0x9009b,	0x9009c,	0x9009d,	0x9009e,
	0x9009f,	0x900a0,	0x900a1,	0x900a2,	0x900a3,	0x40000,	0x40020,	0x40040,
	0x40060,	0x40001,	0x40021,	0x40041,	0x40061,	0x40002,	0x40022,	0x40042,
	0x40062,	0x40003,	0x40023,	0x40043,	0x40063,	0x40004,	0x40024,	0x40044,
	0x40064,	0x40005,	0x40025,	0x40045,	0x40065,	0x40006,	0x40026,	0x40046,
	0x40066,	0x40007,	0x40027,	0x40047,	0x40067,	0x40008,	0x40028,	0x40048,
	0x40068,	0x40009,	0x40029,	0x40049,	0x40069,	0x4000a,	0x4002a,	0x4004a,
	0x4006a,	0x4000b,	0x4002b,	0x4004b,	0x4006b,	0x4000c,	0x4002c,	0x4004c,
	0x4006c,	0x4000d,	0x4002d,	0x4004d,	0x4006d,	0x4000e,	0x4002e,	0x4004e,
	0x4006e,	0x4000f,	0x4002f,	0x4004f,	0x4006f,	0x40010,	0x40030,	0x40050,
	0x40070,	0x40011,	0x40031,	0x40051,	0x40071,	0x40012,	0x40032,	0x40052,
	0x40072,	0x40013,	0x40033,	0x40053,	0x40073,	0x40014,	0x40034,	0x40054,
	0x40074,	0x40015,	0x40035,	0x40055,	0x40075,	0x40016,	0x40036,	0x40056,
	0x40076,	0x40017,	0x40037,	0x40057,	0x40077,	0x40018,	0x40038,	0x40058,
	0x40078,	0x40019,	0x40039,	0x40059,	0x40079,	0x4001a,	0x4003a,	0x4005a,
	0x4007a,	0x900a4,	0x900a5,	0x900a6,	0x900a7,	0x900a8,	0x900a9,	0x900aa,
	0x900ab,	0x900ac,	0x900ad,	0x900ae,	0x900af,	0x900b0,	0x900b1,	0x900b2,
	0x900b3,	0x900b4,	0x900b5,	0x900b6,	0x900b7,	0x900b8,	0x900b9,	0x900ba,
	0x900bb,	0x900bc,	0x900bd,	0x900be,	0x900bf,	0x900c0,	0x900c1,	0x900c2,
	0x900c3,	0x900c4,	0x900c5,	0x900c6,	0x900c7,	0x900c8,	0x900c9,	0x900ca,
	0x900cb,	0x900cc,	0x900cd,	0x900ce,	0x900cf,	0x900d0,	0x900d1,	0x900d2,
	0x900d3,	0x900d4,	0x900d5,	0x900d6,	0x900d7,	0x900d8,	0x900d9,	0x900da,
	0x900db,	0x900dc,	0x900dd,	0x900de,	0x900df,	0x900e0,	0x900e1,	0x900e2,
	0x900e3,	0x900e4,	0x900e5,	0x900e6,	0x900e7,	0x900e8,	0x900e9,	0x900ea,
	0x900eb,	0x900ec,	0x900ed,	0x900ee,	0x900ef,	0x900f0,	0x900f1,	0x900f2,
	0x900f3,	0x900f4,	0x900f5,	0x900f6,	0x900f7,	0x900f8,	0x900f9,	0x900fa,
	0x900fb,	0x900fc,	0x900fd,	0x900fe,	0x900ff,	0x90100,	0x90101,	0x90102,
	0x90103,	0x90104,	0x90105,	0x90106,	0x90107,	0x90108,	0x90109,	0x9010a,
	0x9010b,	0x9010c,	0x9010d,	0x9010e,	0x9010f,	0x90110,	0x90111,	0x90112,
	0x90113,	0x90114,	0x90115,	0x90116,	0x90117,	0x90118,	0x90119,	0x9011a,
	0x9011b,	0x9011c,	0x9011d,	0x9011e,	0x9011f,	0x90120,	0x90121,	0x90122,
	0x90123,	0x90124,	0x90125,	0x90126,	0x90127,	0x90128,	0x90129,	0x9012a,
	0x9012b,	0x9012c,	0x9012d,	0x9012e,	0x9012f,	0x90130,	0x90131,	0x90132,
	0x90133,	0x90134,	0x90135,	0x90136,	0x90137,	0x90138,	0x90139,	0x9013a,
	0x9013b,	0x9013c,	0x9013d,	0x9013e,	0x9013f,	0x90140,	0x90141,	0x90142,
	0x90143,	0x90144,	0x90145,	0x90146,	0x90147,	0x90148,	0x90149,	0x9014a,
	0x9014b,	0x9014c,	0x9014d,	0x9014e,	0x9014f,	0x90150,	0x90151,	0x90152,
	0x90153,	0x90154,	0x90155,	0x90156,	0x90157,	0x90158,	0x90159,	0x9015a,
	0x9015b,	0x9015c,	0x9015d,	0x9015e,	0x9015f,	0x90160,	0x90161,	0x90162,
	0x90163,	0x90164,	0x90165,	0x90166,	0x90167,	0x90168,	0x90169,	0x9016a,
	0x9016b,	0x9016c,	0x9016d,	0x9016e,	0x9016f,	0x90170,	0x90171,	0x90172,
	0x90173,	0x90174,	0x90175,	0x90176,	0x90177,	0x90178,	0x90179,	0x9017a,
	0x9017b,	0x9017c,	0x9017d,	0x9017e,	0x9017f,	0x90180,	0x90181,	0x90006,
	0x90007,	0x90008,	0x90009,	0x9000a,	0x9000b,	0xd00e7,	0x90017,	0x9001f,
	0x90026,	0x400d0,	0x400d1,	0x400d2,	0x400d3,	0x400d4,	0x400d5,	0x400d6,
	0x400d7,	0x200be,	0x2000b,	0x2000c,	0x2000d,	0x2000e,	0x9000c,	0x9000d,
	0x9000e,	0x9000f,	0x90010,	0x90011,	0x90012,	0x90013,	0x20010,	0x20011,
	0x40080,	0x40081,	0x40082,	0x40083,	0x40084,	0x40085,	0x400fd,	0x10011,
	0x10012,	0x10013,	0x10018,	0x10002,	0x100b2,	0x101b4,	0x102b4,	0x103b4,
	0x104b4,	0x105b4,	0x106b4,	0x107b4,	0x108b4,	0x11011,	0x11012,	0x11013,
	0x11018,	0x11002,	0x110b2,	0x111b4,	0x112b4,	0x113b4,	0x114b4,	0x115b4,
	0x116b4,	0x117b4,	0x118b4,	0x12011,	0x12012,	0x12013,	0x12018,	0x12002,
	0x120b2,	0x121b4,	0x122b4,	0x123b4,	0x124b4,	0x125b4,	0x126b4,	0x127b4,
	0x128b4,	0x13011,	0x13012,	0x13013,	0x13018,	0x13002,	0x130b2,	0x131b4,
	0x132b4,	0x133b4,	0x134b4,	0x135b4,	0x136b4,	0x137b4,	0x138b4,	0x20089,
	0xc0080,	0x200cb,	0x10068,	0x10069,	0x10168,	0x10169,	0x10268,	0x10269,
	0x10368,	0x10369,	0x10468,	0x10469,	0x10568,	0x10569,	0x10668,	0x10669,
	0x10768,	0x10769,	0x10868,	0x10869,	0x100aa,	0x10062,	0x10001,	0x100a0,
	0x100a1,	0x100a2,	0x100a3,	0x100a4,	0x100a5,	0x100a6,	0x100a7,	0x11068,
	0x11069,	0x11168,	0x11169,	0x11268,	0x11269,	0x11368,	0x11369,	0x11468,
	0x11469,	0x11568,	0x11569,	0x11668,	0x11669,	0x11768,	0x11769,	0x11868,
	0x11869,	0x110aa,	0x11062,	0x11001,	0x110a0,	0x110a1,	0x110a2,	0x110a3,
	0x110a4,	0x110a5,	0x110a6,	0x110a7,	0x12068,	0x12069,	0x12168,	0x12169,
	0x12268,	0x12269,	0x12368,	0x12369,	0x12468,	0x12469,	0x12568,	0x12569,
	0x12668,	0x12669,	0x12768,	0x12769,	0x12868,	0x12869,	0x120aa,	0x12062,
	0x12001,	0x120a0,	0x120a1,	0x120a2,	0x120a3,	0x120a4,	0x120a5,	0x120a6,
	0x120a7,	0x13068,	0x13069,	0x13168,	0x13169,	0x13268,	0x13269,	0x13368,
	0x13369,	0x13468,	0x13469,	0x13568,	0x13569,	0x13668,	0x13669,	0x13768,
	0x13769,	0x13868,	0x13869,	0x130aa,	0x13062,	0x13001,	0x130a0,	0x130a1,
	0x130a2,	0x130a3,	0x130a4,	0x130a5,	0x130a6,	0x130a7,	0x80   ,	0x1080 ,
	0x2080 ,	0x3080 ,	0x4080 ,	0x5080 ,	0x6080 ,	0x7080 ,	0x8080 ,	0x9080 ,
	0x10020,	0x10080,	0x10081,	0x100d0,	0x100d1,	0x1008c,	0x1008d,	0x10180,
	0x10181,	0x101d0,	0x101d1,	0x1018c,	0x1018d,	0x100c0,	0x100c1,	0x101c0,
	0x101c1,	0x102c0,	0x102c1,	0x103c0,	0x103c1,	0x104c0,	0x104c1,	0x105c0,
	0x105c1,	0x106c0,	0x106c1,	0x107c0,	0x107c1,	0x108c0,	0x108c1,	0x100ae,
	0x100af,	0x11020,	0x11080,	0x11081,	0x110d0,	0x110d1,	0x1108c,	0x1108d,
	0x11180,	0x11181,	0x111d0,	0x111d1,	0x1118c,	0x1118d,	0x110c0,	0x110c1,
	0x111c0,	0x111c1,	0x112c0,	0x112c1,	0x113c0,	0x113c1,	0x114c0,	0x114c1,
	0x115c0,	0x115c1,	0x116c0,	0x116c1,	0x117c0,	0x117c1,	0x118c0,	0x118c1,
	0x110ae,	0x110af,	0x12020,	0x12080,	0x12081,	0x120d0,	0x120d1,	0x1208c,
	0x1208d,	0x12180,	0x12181,	0x121d0,	0x121d1,	0x1218c,	0x1218d,	0x120c0,
	0x120c1,	0x121c0,	0x121c1,	0x122c0,	0x122c1,	0x123c0,	0x123c1,	0x124c0,
	0x124c1,	0x125c0,	0x125c1,	0x126c0,	0x126c1,	0x127c0,	0x127c1,	0x128c0,
	0x128c1,	0x120ae,	0x120af,	0x13020,	0x13080,	0x13081,	0x130d0,	0x130d1,
	0x1308c,	0x1308d,	0x13180,	0x13181,	0x131d0,	0x131d1,	0x1318c,	0x1318d,
	0x130c0,	0x130c1,	0x131c0,	0x131c1,	0x132c0,	0x132c1,	0x133c0,	0x133c1,
	0x134c0,	0x134c1,	0x135c0,	0x135c1,	0x136c0,	0x136c1,	0x137c0,	0x137c1,
	0x138c0,	0x138c1,	0x130ae,	0x130af,	0x90201,	0x90202,	0x90203,	0x90205,
	0x90206,	0x90207,	0x90208,	0x20020,	0x20077,	0x20072,	0x20073,	0x400c0,
	0x10040,	0x10140,	0x10240,	0x10340,	0x10440,	0x10540,	0x10640,	0x10740,
	0x10840,	0x11040,	0x11140,	0x11240,	0x11340,	0x11440,	0x11540,	0x11640,
	0x11740,	0x11840,	0x12040,	0x12140,	0x12240,	0x12340,	0x12440,	0x12540,
	0x12640,	0x12740,	0x12840,	0x13040,	0x13140,	0x13240,	0x13340,	0x13440,
	0x13540,	0x13640,	0x13740,	0x13840

};


void wait_loop(unsigned int wait_counter)
{
	unsigned int i;

	for (i = 0; i < wait_counter; i++) 
	{
		__asm__("nop");
	}
}

void apb_ctl_before_retention(void)
{
	volatile uint16_t rd_data;

	wait_loop(10000);
	ctl_apb_wr(0x490,0x00000000);   //blocks AXI ports from taking anymore transactions

	while (1) 
	{
		rd_data = ctl_apb_rd(0x3fc);
		if (rd_data == 0) 
		{
			break;
		}
	}

	ctl_apb_wr(0x30,0x00000020);    //Causes system to move to self refresh state

	rd_data = ctl_apb_rd(0x4);
	while (((rd_data&0x30)!= 0x20) | ((rd_data&0x300) != 0x200)) 
	{
		rd_data = ctl_apb_rd(0x4);
	}

	ctl_apb_wr(0x320,0x00000000);   //SWCTL
	ctl_apb_wr(0x1b0,0x00001f70);   //Set dfi_init_start to 1

	rd_data = ctl_apb_rd(0x1bc);
	while((rd_data & 0x01)!= 0)
	{
		rd_data = ctl_apb_rd(0x1bc);    //Wait PHY de-assert dfi_init_complete
	}

	ctl_apb_wr(0x1b0,0x00001f50);   //Set dfi_init_start to 0

	rd_data = ctl_apb_rd(0x1bc);
	while((rd_data & 0x01)!= 1) 
	{
		rd_data = ctl_apb_rd(0x1bc);  //Wait PHY assert dfi_init_complete
	}

	MOON0_REG->sft_cfg[14] = 0x00200000;  // 1->0: PwrOKIn MO_DDRPHY_PWROKIN ddrphy pwrokin
	wait_loop(10000);                        // When PWROKIN is 0, PHY input signals need be valid at least 10ns
	MOON0_REG->sft_cfg[14] = 0x00010000;  // 1->0: assert DDRCTL APB RST_N
	MOON0_REG->sft_cfg[14] = 0x00080000;  // 1->0: assert DDRPHY APB RST_N
	MOON0_REG->sft_cfg[14] = 0x00020000;  // 1->0: assert DDRCTL AXI RST_N
	MOON0_REG->sft_cfg[14] = 0x00040000;  // 1->0: assert DDRCTL AHB RST_N
	MOON0_REG->sft_cfg[14] = 0x00100000;  // 1->0: assert DDRDFI RST_N

	MOON0_REG->sft_cfg[2]  = 0x00040004;  //RF_MASK_V_SET(1 << 2);
	MOON0_REG->sft_cfg[2]  = 0x00080008;  //RF_MASK_V_SET(1 << 3);
	MOON0_REG->sft_cfg[2]  = 0x00100010;  //RF_MASK_V_SET(1 << 4);
	MOON0_REG->sft_cfg[2]  = 0x00200020;  //RF_MASK_V_SET(1 << 5);

}

int dram_test(void)
{
	uint8_t   *wr_src_8b  ;
	uint16_t  *wr_src_16b ;
	uint32_t  *wr_src_32b ;
	uint8_t   value_8b    ;
	uint16_t  value_16b   ;
	uint32_t  value_32b   ;
	uint32_t  *rd_src_32b ;
	uint8_t   *rd_src_8b  ;
	uint8_t   count, flip;

	unsigned char *des_adr = (unsigned char *)0x50000000;

	wr_src_16b   = (uint16_t *)(des_adr);
	value_16b    = 0;
	do {
		*wr_src_16b = value_16b;
		wr_src_16b  = wr_src_16b + 1;
		value_16b   = value_16b  + 1;
	} while ((ulong)wr_src_16b < (ulong)(des_adr + 0x1000));

	rd_src_32b   = (uint32_t *)(des_adr);
	value_16b    = 0;
	do {
		value_32b = ((value_16b + 1) << 16) | ((value_16b + 0) <<  0) ;
		if (value_32b != *rd_src_32b) 
		{
			return -1;
		}
		rd_src_32b = rd_src_32b + 1;
		value_16b  = value_16b  + 2;
	} while ((ulong)rd_src_32b < (ulong)(des_adr + 0x1000));

	return 0;
}

static uint32_t sum32(uint32_t sum, uint8_t *data, int len)
{
        int val = 0, pos =0;


        for (; pos + 4 <= len; pos += 4) {
                sum += *(int *)(data + pos);
        }

        // word0: 3 2 1 0
        // word1: _ 6 5 4
        for (; len - pos; len--)
                val = (val << 8) | data[len - 1];

        sum += val;

        return sum;
}
void ddr_retention_save(void)
{
	// Size of ddr phy register is 16 bit.
	volatile uint16_t * const ddr_ret = (uint16_t * const) CM4_SRAM_RET_ADDRESS;  // SRAM (CM4) CPU view

	// Enabling Ucclk (PMU)
	dwc_ddrphy_apb_wr(0xd0000, 0x0);
	dwc_ddrphy_apb_wr(0xc0080, 0x3);

	// Save ddr phy registers to SRAM.
	for (int i=0; i < RET_CSRS_CNT; i++) {
		ddr_ret[i] = DWC_PHY_REG(ret_ddrphy_addr[i]);
	}

	// Disabling Ucclk (PMU)
	dwc_ddrphy_apb_wr(0xc0080, 0x2);
	dwc_ddrphy_apb_wr(0xd0000, 0x1);


	printf("ddr_retention_save \n");


	apb_ctl_before_retention();
}


int dwc_umctl2_init_before_ctl_rst(void)
{

	ctl_apb_wr(0x304, 0x00000001);
	ctl_apb_wr(0x030, 0x00000001);
	//ctl_apb_rd(0x004, 0x00000000);
	ctl_apb_rd(0x004);

	ctl_apb_wr(0x000 , 0x83080020);
	ctl_apb_wr(0x020 , 0x00001202);
	ctl_apb_wr(0x024 , 0x00000000);
	ctl_apb_wr(0x02c , 0x00000000);
	ctl_apb_wr(0x030 , 0x00000020);
	ctl_apb_wr(0x034 , 0x00400010);
	ctl_apb_wr(0x050 , 0x90210004);
	ctl_apb_wr(0x054 , 0x002b0000);
	ctl_apb_wr(0x060 , 0x00000000);
	ctl_apb_wr(0x064 , 0x000c0098);
	ctl_apb_wr(0x068 , 0x00480000);
	ctl_apb_wr(0x0d0 , 0xc0020003);
	ctl_apb_wr(0x0d4 , 0x00010002);
	ctl_apb_wr(0x0d8 , 0x00000d00);
	ctl_apb_wr(0x0dc , 0x0054002d);
	ctl_apb_wr(0x0e0 , 0x00310020);
	ctl_apb_wr(0x0e4 , 0x00040009);
	ctl_apb_wr(0x0e8 , 0x00660047);
	ctl_apb_wr(0x0ec , 0x001c0047);
	ctl_apb_wr(0x0f4 , 0x0000f53f);
	ctl_apb_wr(0x100 , 0x1b201a22);
	ctl_apb_wr(0x104 , 0x00060633);
	ctl_apb_wr(0x108 , 0x070e1214);
	ctl_apb_wr(0x10c , 0x0080c000);
	ctl_apb_wr(0x110 , 0x0f04080f);
	ctl_apb_wr(0x114 , 0x02040c0c);
	ctl_apb_wr(0x118 , 0x01010007);
	ctl_apb_wr(0x11c , 0x00000402);
	ctl_apb_wr(0x120 , 0x00000000);
	ctl_apb_wr(0x124 , 0x00000000);
	ctl_apb_wr(0x128 , 0x00000000);
	ctl_apb_wr(0x12c , 0x00000000);
	ctl_apb_wr(0x130 , 0x00020000);
	ctl_apb_wr(0x134 , 0x0c100002);
	ctl_apb_wr(0x138 , 0x00000136);
	ctl_apb_wr(0x13c , 0x00000000);
	ctl_apb_wr(0x180 , 0x13200018);
	ctl_apb_wr(0x184 , 0x028b282b);
	ctl_apb_wr(0x188 , 0x00000000);
	ctl_apb_wr(0x190 , 0x0397820a);
	ctl_apb_wr(0x194 , 0x000a0101);
	ctl_apb_wr(0x198 , 0x01000000);
	ctl_apb_wr(0x19c , 0x00000000);
	ctl_apb_wr(0x1a0 , 0xc0300018);
	ctl_apb_wr(0x1a4 , 0x0042009c);
	ctl_apb_wr(0x1a8 , 0x80000000);
	ctl_apb_wr(0x1b0 , 0x00000041);
	ctl_apb_wr(0x1b4 , 0x0000170a);
	ctl_apb_wr(0x1b8 , 0x00000004);
	ctl_apb_wr(0x1c0 , 0x00000000);
	ctl_apb_wr(0x1c4 , 0x80000000);
	ctl_apb_wr(0x200 , 0x00000017);

	
	ctl_apb_wr(0x204 , 0x00080808);
	ctl_apb_wr(0x208 , 0x00000000);
	ctl_apb_wr(0x20c , 0x00000000);
	ctl_apb_wr(0x210 , 0x00001F1F);
	ctl_apb_wr(0x214 , 0x070F0707);
	ctl_apb_wr(0x218 , 0x07070707);
	ctl_apb_wr(0x21c , 0x00000F08);
	ctl_apb_wr(0x220 , 0x00000000);
	ctl_apb_wr(0x224 , 0x07070707);
	ctl_apb_wr(0x228 , 0x07070707);
	ctl_apb_wr(0x22c , 0x00000007);
	ctl_apb_wr(0x240 , 0x00000000);
	ctl_apb_wr(0x244 , 0x00000000);
	ctl_apb_wr(0x250 , 0x00003d04);
	ctl_apb_wr(0x254 , 0x000000f0);
	ctl_apb_wr(0x25c , 0x0f000001);
	ctl_apb_wr(0x264 , 0x0f00007f);
	ctl_apb_wr(0x26c , 0x0f00007f);
	ctl_apb_wr(0x300 , 0x00000000);
	ctl_apb_wr(0x304 , 0x00000000);
	ctl_apb_wr(0x30c , 0x00000000);
	ctl_apb_wr(0x320 , 0x00000001);
	ctl_apb_wr(0x328 , 0x00000000);
	ctl_apb_wr(0x36c , 0x00000000);
	ctl_apb_wr(0x400 , 0x00000000);
	ctl_apb_wr(0x404 , 0x0000700f);
	ctl_apb_wr(0x408 , 0x0000700f);
	ctl_apb_wr(0x494 , 0x0020000d);
	ctl_apb_wr(0x498 , 0x00000000);
	ctl_apb_wr(0x49c , 0x00000e0d);
	ctl_apb_wr(0x4a0 , 0x00000000);
	ctl_apb_wr(0x4b4 , 0x0000700f);
	ctl_apb_wr(0x4b8 , 0x0000700f);
	ctl_apb_wr(0x544 , 0x0020000d);
	ctl_apb_wr(0x548 , 0x00000000);
	ctl_apb_wr(0x54c , 0x00000e0d);
	ctl_apb_wr(0x550 , 0x00000000);
	ctl_apb_wr(0x564 , 0x0000700f);
	ctl_apb_wr(0x568 , 0x0000700f);
	ctl_apb_wr(0x5f4 , 0x0020000d);
	ctl_apb_wr(0x5f8 , 0x00000000);
	ctl_apb_wr(0x5fc , 0x00000e0d);
	ctl_apb_wr(0x600 , 0x00000000);
	ctl_apb_wr(0x614 , 0x0000700f);
	ctl_apb_wr(0x618 , 0x0000700f);
	ctl_apb_wr(0x6a4 , 0x0020000d);
	ctl_apb_wr(0x6a8 , 0x00000000);
	ctl_apb_wr(0x6ac , 0x00000e0d);
	ctl_apb_wr(0x6b0 , 0x00000000);
	ctl_apb_wr(0x490 , 0x00000001);
	
	ctl_apb_wr(0x540 , 0x00000001);
	ctl_apb_wr(0x5f0 , 0x00000001);
	ctl_apb_wr(0x6a0 , 0x00000001);
	
	return 0;
}

int dwc_umctl2_init_after_ctl_rst(void)
{

	ctl_apb_wr(0x304, 0x00000000);
	//ctl_apb_rd(0x030, 0x00000020);
	ctl_apb_rd(0x030);

	ctl_apb_wr(0x030, 0x00000122);
	//ctl_apb_rd(0x030, 0x00000020);
	ctl_apb_rd(0x030);

	ctl_apb_wr(0x030, 0x00000120);
	//ctl_apb_rd(0x1c4, 0xcf000000);
	ctl_apb_rd(0x1c4);

	ctl_apb_wr(0x1c4, 0xc8000000);
	ctl_apb_wr(0x320, 0x00000000);
	ctl_apb_wr(0x1b0, 0x00000054);
	ctl_apb_wr(0x1b0, 0x00000054);
	ctl_apb_wr(0x304, 0x00000002);

	return 0;
}

void apb_ctl_after_retention(void)
{
	volatile uint32_t rd_data;

	MOON3_REG->sft_cfg[11] = 0x00180008;  //PLLD PSTDIV
	MOON3_REG->sft_cfg[11] = 0x7f801000;  //PLLD FBKDIV 32
	//while(((MOON3_REG->sft_cfg[13]) & (1<<8)) != (1<<8));  //wait pll lock

	MOON0_REG->sft_cfg[2]  = 0x00040000;  //RF_MASK_V_CLR(1 << 2);
	MOON0_REG->sft_cfg[2]  = 0x00080000;  //RF_MASK_V_CLR(1 << 3);
	MOON0_REG->sft_cfg[2]  = 0x00100000;  //RF_MASK_V_CLR(1 << 4);
	MOON0_REG->sft_cfg[2]  = 0x00200000;  //RF_MASK_V_CLR(1 << 5);
	wait_loop(1000);
	MOON0_REG->sft_cfg[14] = 0x00200020; // 0->1: PwrOKIn MO_DDRPHY_PWROKIN ddrphy pwrokin
	wait_loop(1000);
	wait_loop(1000);
	MOON0_REG->sft_cfg[14] = 0x00010001;  // 0->1: de-assert DDRCTL APB RST_N
	MOON0_REG->sft_cfg[14] = 0x00080008;  // 0->1: de-assert DDRPHY APB RST_N

	wait_loop(1000);

	// -------------------------------------------------------
	// 2.
	// -------------------------------------------------------
	// DRAM MRS SETTING

	dwc_umctl2_init_before_ctl_rst();

	ctl_apb_wr(0x0d0,0xc0030003);   //skips the DRAM init routine and starts up in self_refresh mode
	ctl_apb_wr(0x30,0x00000020);    //Keep system on self refresh state
	ctl_apb_wr(0x1b0,0x00000050);   //indicates to controller that PHY has completed re-training/initialization
	
	MOON0_REG->sft_cfg[14] = 0x00020002;  // 0->1: de-assert DDRCTL AXI RST_N
	MOON0_REG->sft_cfg[14] = 0x00040004;  // 0->1: de-assert DDRCTL AHB RST_N
	MOON0_REG->sft_cfg[14] = 0x00100010;  // 0->1: de-assert DDRDFI RST_N
	wait_loop(1000);
	wait_loop(1000);

	dwc_umctl2_init_after_ctl_rst();

	wait_loop(1000);

	// -------------------------------------------------------
	// 3.
	// -------------------------------------------------------

	volatile uint16_t * const ddr_ret = (uint16_t *) CM4_SRAM_RET_ADDRESS;	// SRAM (CM4) CPU view

	dwc_ddrphy_apb_wr(0xd0000,0x0); // DWC_DDRPHYA_APBONLY0_MicroContMuxSel
	dwc_ddrphy_apb_wr(0xc0080,0x3); // DWC_DDRPHYA_DRTUB0_UcclkHclkEnables

	// Restore ddr phy registers from SRAM.
	for (int i=0; i < RET_CSRS_CNT; i++) {
		DWC_PHY_REG(ret_ddrphy_addr[i]) = ddr_ret[i];
	}

	dwc_ddrphy_apb_wr(0xc0080,0x2); // DWC_DDRPHYA_DRTUB0_UcclkHclkEnables
	dwc_ddrphy_apb_wr(0xd0000,0x1); // DWC_DDRPHYA_APBONLY0_MicroContMuxSel

	ctl_apb_wr(0x1b0,0x00000070);   //trigger dfi_init_start

	while(1)
	{
		rd_data = ctl_apb_rd(0x1bc);
		if(rd_data == 1)
		{
		 break;
		}
	}

	ctl_apb_wr(0x1b0,0x00000050);
	ctl_apb_wr(0x1b0,0x00000051); //trigger SDRAM initilaztion.
	ctl_apb_wr(0x030,0x00000000); //PWRCTL
	ctl_apb_wr(0x1c4,0x00000001);   //enable the PHY master interface.
	ctl_apb_wr(0x304,0x00000000);   //enable dq and hif.
	rd_data = ctl_apb_rd(0x4);
	while(((rd_data & 0x30)!=0x00) || ((rd_data&0x07) != 0x01))
	{
		rd_data = ctl_apb_rd(0x4);      //Wait exit self_refresh and entry normal mode
	}

	ctl_apb_wr(0x490,0x00000001);   //no longer blocks AXI ports from taking anymore transactions
}

void ddr_retention_load(void)
{
	//while(((MOON3_REG->sft_cfg[13]) & (1<<8)) != (1<<8));  //wait pll lock
	wait_loop(1000);

	apb_ctl_after_retention();

	

	printf("ddr_retention_load \n");
}
